#include "elfx.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>



//解析64位elf文件
elf64_t * parse_elf64_file(char * path ){
    
    elf64_t * elf = malloc(sizeof(elf64_t));
    FILE * file = fopen(path, "r");
    struct stat * stt = malloc(sizeof(struct stat));  
    stat(path,stt); 
    elf->stat = stt;
    elf->bytes.ptr = malloc(elf_size(elf));  
    elf->bytes.len = elf_size(elf);; 
    size_t len = fread(elf_bytes_addr(elf),512, stt->st_size/512+1,file);
    
    //记录ELF文件头地址
    elf->ehdr = (Elf64_Ehdr*)elf_bytes_offset_addr(elf,0);
    
    //记录段表地址
    elf->shdr_vec = (Elf64_Shdr*)elf_bytes_offset_addr(elf, ((Elf64_Ehdr*)elf->ehdr)->e_shoff);
    //记录段表字符串段描述符的地址 
    elf->shstrtab_shdr = elf->shdr_vec+elf->ehdr->e_shstrndx; 
    //记录段表字符串段的内存区
    elf->shstrtab.ptr = elf_bytes_offset_addr(elf,elf->shstrtab_shdr->sh_offset );
    elf->shstrtab.len = elf->shstrtab_shdr->sh_size;

    //定位各种段描述符
    for(int i=0;i<elf->ehdr->e_shnum;i++){
        //跳过.shstrtab段
        if(i==elf->ehdr->e_shstrndx)continue;
        Elf64_Shdr * shdr = elf->shdr_vec + i;
        switch( shdr->sh_type ){

            //记录 .dynsym动态符号段描述符
            case SHT_DYNSYM: elf->dyn_sym_shdr = shdr; break;
            //记录.symtab段描述符
            case SHT_SYMTAB: elf->sym_shdr = shdr;break;
            //记录.strtab段描述符
            case SHT_STRTAB: elf->strtab_shdr = shdr;break; 
            //记录.text段描述符
            case SHT_PROGBITS:
                if( shdr->sh_flags & SHF_EXECINSTR ){
                    elf->text_shdr = shdr;
                }
                break;
            //记录重定位表段描述符
            case SHT_RELA:
            case SHT_REL:
                elf->rel_shdr_vec = realloc(elf->rel_shdr_vec,sizeof(Elf64_Shdr *)*(elf->rel_shdr_vec_len+1));
                *(elf->rel_shdr_vec+elf->rel_shdr_vec_len++) = shdr;   
                break;
       }
    }
    //记录字符串表
    elf->strtab.ptr = elf_bytes_offset_addr(elf,elf->strtab_shdr->sh_offset);
    elf->strtab.len = elf->strtab_shdr->sh_size;
   
    if( elf->sym_shdr ){
        //记录符号表
        elf->sym_vec = (Elf64_Sym *)elf_bytes_offset_addr(elf,elf->sym_shdr->sh_offset);
    }
    if( elf->dyn_sym_shdr ){
        //记录动态符号表
        elf->dyn_sym_vec = (Elf64_Sym *)elf_bytes_offset_addr(elf,elf->dyn_sym_shdr->sh_offset);
    }
    return elf;
}


static char * symtab_shndx(elf64_t * elf, int n ){
    switch(n){
        case 0xfff1: return "ABS";
        case 0xfff2: return "COMMON";
        case 0: return "UNDEF";
        default: return get_shstr_in_offset(elf,(elf->shdr_vec+n)->sh_name); 
    }
}

static char * st_type_map_sparc(int n){
    switch(n){
        case 13: return "STT_SPARC_REGISTER";
    }
    return NULL;
}

static char * st_type_map_hppa(int n){
    switch(n){
        case 13: return "STT_PARISC_MILLICODE";
        case 11: return "STT_HP_OPAQUE";
        case 12: return "STT_HP_STUB";
    }
    return NULL;
}

static char * st_type_map_arm(int n){
    switch(n){
        case 13: return "STT_ARM_TFUNC";
        case 15: return "STT_ARM_16BIT";
    }
    return NULL;
}

char * st_type_map(elf64_t * elf,int n){
    char * ret = NULL;
    switch(elf->ehdr->e_machine){
        case EM_SPARC: ret = st_type_map_sparc(n);break;
        case EM_PARISC:ret = st_type_map_hppa(n);break;
        case EM_ARM: ret = st_type_map_arm(n);break; 
    }
    if(ret)return ret;
    
    switch(n){
        case 0: return "STT_NOTYPE";
        case 1: return "STT_OBJECT";
        case 2: return "STT_FUNC";
        case 3: return "STT_SECTION";
        case 4: return "STT_FILE";
        case 5: return "STT_COMMON";
        case 6: return "STT_TLS";
        case 7: return "STT_NUM";
        case 10: return "STT_LOOS/GNU_IFUNC";
        case 12: return "STT_HIOS";
        case 13: return "STT_LOPROC";
        case 15: return "STT_HIPROC";
    }
    return "STT_NOTYPE";
}

static char * st_bind_info(elf64_t * elf, int n){
    if(n==13 && elf->ehdr->e_machine==EM_MIPS){
        return "STB_MIPS_SPLIT_COMMON"; 
    }
    switch(n){
        case 0: return "STB_LOCAL";
        case 1: return "STB_GLOBAL";
        case 2: return "STB_WEAK";
        case 3: return "STB_NUM";
        case 10: return "STB_LOOS/GNU_UNIQUE";
        case 12: return "STB_HIOS";
        case 13: return "STB_LOPROC";
        case 14: return "STB_HIPROC";
    }
    return "STB_NONE";
}

//打印elf文件头
void print_ehdr(elf64_t * elf){
    printf(">>---------[ ELF文件头 ]---->\n");
    printf("Magic:               ");
    for(int i=0;i<EI_NIDENT;i++){
        printf("%02x ",elf->ehdr->e_ident[i]); 
    }
    putchar('\n');
    printf("Class:               %s");
    switch(elf->ehdr->e_ident[4]){
        case 0x1:puts("ELF32");break;
        case 0x2:puts("ELF64");break;
        default: puts("未知");break;
    }
    printf("Data:                2's complement,");
    switch( elf->ehdr->e_ident[5] ){
        case 0x1: puts("little endian");break;
        default: puts("big endian");break;
    }
    printf("Version:             %d(%s)\n",elf->ehdr->e_ident[6],e_version_map(elf->ehdr->e_ident[6])+3);   
    printf("OS/ABI:              UNIX-System V\n"); 
    printf("ABI Version:         0\n");
    printf("ELF文件类型:         %s\n",e_type_map(elf->ehdr->e_type)+3);
    printf("CPU平台:             %s\n",e_machine_map(elf->ehdr->e_machine)+3);
    printf("ELF文件版本号:       %d\n",elf->ehdr->e_version);
    printf("程序入口地址:        0x%08lx\n",elf->ehdr->e_entry);
    printf("e_phoff:             0x%08lx\n",elf->ehdr->e_phoff);
    printf("段表在文件中的偏移:  0x%08lx\n",elf->ehdr->e_shoff);
    printf("ELF标志位:           0x%08lx\n",elf->ehdr->e_flags);
    printf("ELF文件头大小:       %d\n",elf->ehdr->e_ehsize);
    printf("e_phentsize:         %d\n",elf->ehdr->e_phentsize);
    printf("e_phnum:             %d\n",elf->ehdr->e_phnum);
    printf("段表描述符大小:      %d\n",elf->ehdr->e_shentsize);
    printf("段表描述符数量:      %d\n",elf->ehdr->e_shnum);
    printf("段表字符串表下标:    %d\n",elf->ehdr->e_shstrndx);
}

void print_shdr(elf64_t * elf){
    printf(">>---------[ 段表 ]---->\n");
    printf("序号\t段名\t\t    虚拟地址\t文件偏移\t段长度\t项数\t对齐\t段类型\n");
    for(int i=0;i<elf_shdr_vec_num(elf);i++){
        Elf64_Shdr * shdr = elf->shdr_vec+i;
        printf("%d\t%-20s0x%08lx\t%d\t\t%d\t%d\t%d\t%s\n",
                i,
                get_shstr_in_offset(elf,shdr->sh_name),
                shdr->sh_addr,
                shdr->sh_offset,
                shdr->sh_size,
                shdr->sh_entsize,
                shdr->sh_addralign,
                sh_type_map(elf,shdr->sh_type)+4
              );  
    }

}

void print_shstrtab(elf64_t * elf){
    printf(">>---------[ shstrtab表 ]---->\n");
    for(int i=0;i<elf->shstrtab_shdr->sh_size;i++){
        char ch = value_in_elf_offset(elf,elf->shstrtab_shdr->sh_offset+i);
        if(ch){
            putchar(ch);
        }else{
            putchar(' ');
        }
    }
    putchar('\n');
}

void print_strtab(elf64_t * elf){
    printf(">>---------[ strtab表 ]---->\n");
    for(int i=0;i<elf->strtab_shdr->sh_size;i++){
        char ch = value_in_elf_offset(elf,elf->strtab_shdr->sh_offset+i);
        if(ch){
            putchar(ch);
        }else{
            putchar(' ');
        }
    }
    putchar('\n');
}

#define SEL_SYM 1
#define SEL_DYN 2

void print_symtab(elf64_t * elf,int sel){
    Elf64_Sym * sym_vec = NULL;
    int num = 0;
    if(sel == SEL_DYN ){
        sym_vec = elf->dyn_sym_vec; 
        num = elf->dyn_sym_shdr->sh_size/elf->dyn_sym_shdr->sh_entsize;
    }else if(sel = SEL_SYM ){
        sym_vec = elf->sym_vec;
        num = elf->sym_shdr->sh_size/elf->sym_shdr->sh_entsize;
    }else{
        return;
    }
    printf(">>---------[ %s符号表 ]---->\n",sel==SEL_DYN?".dynsym":".symtab");
    printf("序号\t符号名\t\t\t\t符号类型\t符号绑定信息\t符号值\t\t符号大小\t符号所在段\n");
    for(int i=0;i< num;i++){
        Elf64_Sym * sym = sym_vec+i;
        printf("%d\t%-30s\t%-10s\t%-10s\t0x%08lx\t%d\t\t%s\n",
                i,
                get_str_in_offset(elf,sym->st_name),
                st_type_map(elf,sym->st_info&0xf)+4,
                st_bind_info(elf,sym->st_info>>4)+4,
                sym->st_value,
                sym->st_size,
                symtab_shndx(elf,sym->st_shndx)
              );
    }

}

//打印所有重定位表
void print_rel_section(elf64_t * elf){
    Elf64_Sym * sym_vec = elf->sym_vec;
    if(!sym_vec){
        sym_vec = elf->dyn_sym_vec;
    }
    for(int i=0;i<elf->rel_shdr_vec_len;i++){
        Elf64_Shdr * shdr = *(elf->rel_shdr_vec+i);
        printf(">>---------[ %s:请到 /usr/include/elf.h文件中查找%s平台相关的重定位类型宏定义,宏名以\"R_\"开头 ]---->\n",get_shstr_in_offset(elf, shdr->sh_name), e_machine_map(elf->ehdr->e_machine)+3);
        printf("序号\t%s\t\t重定位类型\t符号下标\t符号名称\t\t符号所在段\n",elf->ehdr->e_type==ET_REL?"待修正位置首字节在段内偏移":"待修正位置首字节的虚拟地址");
        if(shdr->sh_type == SHT_REL ){
            for(int j=0;j<shdr->sh_size/shdr->sh_entsize;j++){
                Elf64_Rel * rel = (Elf64_Rel*)elf_bytes_offset_addr(elf, shdr->sh_offset+j*shdr->sh_entsize);  
                Elf64_Sym *sym = sym_vec+ELF64_R_SYM(rel->r_info);
                printf("%d\t0x%08lx\t\t\t\t%d\t\t%d\t\t%-25s%s\n",
                        j,
                        rel->r_offset,
                        ELF64_R_TYPE(rel->r_info),
                        ELF64_R_SYM(rel->r_info),
                        get_str_in_offset(elf,sym->st_name),
                        symtab_shndx(elf,sym->st_shndx)
                      );

            }
        }else if(shdr->sh_type == SHT_RELA){
            for(int j=0;j<shdr->sh_size/shdr->sh_entsize;j++){
                Elf64_Rela * rel = (Elf64_Rela*)elf_bytes_offset_addr(elf, shdr->sh_offset+j*shdr->sh_entsize);  
                Elf64_Sym *sym = sym_vec+ELF64_R_SYM(rel->r_info);
                printf("%d\t0x%08lx\t\t\t\t%d\t\t%d\t\t%-25s%s\n",
                        j,
                        rel->r_offset,
                        ELF64_R_TYPE(rel->r_info),
                        ELF64_R_SYM(rel->r_info),
                        get_str_in_offset(elf,sym->st_name),
                        symtab_shndx(elf,sym->st_shndx)

                      );

            }
            
        }
    }
}

void print_elf64(elf64_t * elf, int mask ){

    //打印ELF文件头
    if( mask & PRT_EHDR ){
        print_ehdr(elf);
    }

    //打印段表
    if( mask & PRT_SHDR ){
        print_shdr(elf);
    }

    //打印段表字符串表
    if( mask & PRT_SHSTR ){
        print_shstrtab(elf);
    }

    //打印字符串表
    if(elf->strtab_shdr && mask&PRT_STR ){
        print_strtab(elf);
    }
    
    //打印符号表
    if(elf->sym_shdr && mask & PRT_SYM ){
        print_symtab(elf,SEL_SYM);
    }

    //打印动态符号表
    if(elf->dyn_sym_shdr && mask & PRT_SYM ){
        print_symtab(elf,SEL_DYN);
    }

    //打印重定位表
    if( mask & PRT_REL ){
        print_rel_section(elf);
    }
}

//e_machine的名称映射
char * e_machine_map(int n){
    switch ( n ) {
        case 1: return "EM_M32";
        case 2: return "EM_SPARC";
        case 3: return "EM_386";
        case 4: return "EM_68K";
        case 5: return "EM_88K";
        case 7: return "EM_860";
        case 8: return "EM_MIPS";
        case 9: return "EM_S370";
        case 10: return "EM_MIPS_RS3_LE";
        case 15: return "EM_PARISC";
        case 17: return "EM_VPP500";
        case 18: return "EM_SPARC32PLUS";
        case 19: return "EM_960";
        case 20: return "EM_PPC";
        case 21: return "EM_PPC64";
        case 22: return "EM_S390";
        case 36: return "EM_V800";
        case 37: return "EM_FR20";
        case 38: return "EM_RH32";
        case 39: return "EM_RCE";
        case 40: return "EM_ARM";
        case 41: return "EM_FAKE_ALPHA";
        case 42: return "EM_SH";
        case 43: return "EM_SPARCV9";
        case 44: return "EM_TRICORE";
        case 45: return "EM_ARC";
        case 46: return "EM_H8_300";
        case 47: return "EM_H8_300H";
        case 48: return "EM_H8S";
        case 49: return "EM_H8_500";
        case 50: return "EM_IA_64";
        case 51: return "EM_MIPS_X";
        case 52: return "EM_COLDFIRE";
        case 53: return "EM_68HC12";
        case 54: return "EM_MMA";
        case 55: return "EM_PCP";
        case 56: return "EM_NCPU";
        case 57: return "EM_NDR1";
        case 58: return "EM_STARCORE";
        case 59: return "EM_ME16";
        case 60: return "EM_ST100";
        case 61: return "EM_TINYJ";
        case 62: return "EM_X86_64";
        case 63: return "EM_PDSP";
        case 66: return "EM_FX66";
        case 67: return "EM_ST9PLUS";
        case 68: return "EM_ST7";
        case 69: return "EM_68HC16";
        case 70: return "EM_68HC11";
        case 71: return "EM_68HC08";
        case 72: return "EM_68HC05";
        case 73: return "EM_SVX";
        case 74: return "EM_ST19";
        case 75: return "EM_VAX";
        case 76: return "EM_CRIS";
        case 77: return "EM_JAVELIN";
        case 78: return "EM_FIREPATH";
        case 79: return "EM_ZSP";
        case 80: return "EM_MMIX";
        case 81: return "EM_HUANY";
        case 82: return "EM_PRISM";
        case 83: return "EM_AVR";
        case 84: return "EM_FR30";
        case 85: return "EM_D10V";
        case 86: return "EM_D30V";
        case 87: return "EM_V850";
        case 88: return "EM_M32R";
        case 89: return "EM_MN10300";
        case 90: return "EM_MN10200";
        case 91: return "EM_PJ";
        case 92: return "EM_OPENRISC";
        case 93: return "EM_ARC_A5";
        case 94: return "EM_XTENSA";
        case 183: return "EM_AARCH64";
        case 188: return "EM_TILEPRO";
        case 191: return "EM_TILEGX";
        case 192: return "EM_NUM";
        case 0x9026: return "EM_ALPHA";
        case 0: 
        default: return "EM_NONE";
    }
}

//e_type的名称映射
char * e_type_map(int n ){
    switch( n ){
        case 1: return "ET_REL";
        case 2: return "ET_EXEC";
        case 3: return "ET_DYN";
        case 4: return "ET_CORE";
        case 0xfe00: return "ET_LOOS";
        case 0xfeff: return "ET_HIOS";
        case 0xff00: return "ET_LOPROC";
        case 0xffff: return "ET_HIPROC";
        case 0: 
        default: return "ET_NONE";
    }
}

char * e_version_map(int n ){
    switch( n ){
        case 1: return "EV_CURRENT";
        case 2: return "EV_NUM";
        case 0:
        default: return "EV_NONE";
    }
}

// motorola 68k
char * e_flags_map_68k(int n){
    switch ( n ){
        case 0x00810000: return "EF_CPU32";
        default: return "EF_NONE";
    }
}

// sun sparc
char * e_flags_map_sparc(int n){
    switch ( n ){
        case 3: return "EF_SPARCV9_MM";
        case 0: return "EF_SPARCV9_TSO";
        case 1: return "EF_SPARCV9_PSO";
        case 2: return "EF_SPARCV9_RMO";
        case 0x800000: return "EF_SPARC_LEDATA";
        case 0xFFFF00: return "EF_SPARC_EXT_MASK";
        case 0x000100: return "EF_SPARC_32PLUS";
        case 0x000200: return "EF_SPARC_SUN_US1";
        case 0x000400: return "EF_SPARC_HAL_R1";
        case 0x000800: return "EF_SPARC_SUN_US3";
        default: return "EF_NONE";
    }
}

// mips r3000
char * e_flags_map_mips(int n){
    switch( n ){
        case 1: return "EF_MIPS_NOREORDER";
        case 2: return "EF_MIPS_PIC";
        case 4: return "EF_MIPS_CPIC";
        case 8: return "EF_MIPS_XGOT";
        case 16: return "EF_MIPS_64BIT_WHIRL";
        case 32: return "EF_MIPS_ABI2";
        case 64: return "EF_MIPS_ABI_ON32";
        case 0xf0000000: return "EF_MIPS_ARCH";
        case 0x00000000: return "EF_MIPS_ARCH_1";
        case 0x10000000: return "EF_MIPS_ARCH_2";
        case 0x20000000: return "EF_MIPS_ARCH_3";
        case 0x30000000: return "EF_MIPS_ARCH_4";
        case 0x40000000: return "EF_MIPS_ARCH_5";
        case 0x60000000: return "EF_MIPS_ARCH_32";
        case 0x70000000: return "EF_MIPS_ARCH_64";
        default: return "EF_NONE";
    }
}

// HPPA
char * e_flags_map_hppa( int n ){
    switch( n ){
        case 0x00010000: return "EF_PARISC_TRAPNIL";
        case 0x00020000: return "EF_PARISC_EXT";
        case 0x00040000: return "EF_PARISC_LSB";
        case 0x00080000: return "EF_PARISC_WIDE";
        case 0x00100000: return "EF_PARISC_NO_KABP";
        case 0x00400000: return "EF_PARISC_LAZYSWAP";
        case 0x0000ffff: return "EF_PARISC_ARCH";
        default: return "EF_NONE";
    }
}

// alpha
char * e_flags_map_alpha( int n ){
    switch( n ){
        case 1: return "EF_ALPHA_32BIT";
        case 2: return "EF_ALPHA_CANRELAX";
        default: return "EF_NONE";
    }
}

// ppc
char * e_flags_map_ppc( int n ){
    switch(n ){
        case 0x80000000: return "EF_PPC_EMB";
        case 0x00010000: return "EF_PPC_RELOCATABLE";
        case 0x00008000: return "EF_PPC_RELOCATABLE_LIB";
        case 3: return "EF_PPC64_ABI";
        default: return "EF_NONE";
    }
}

// arm
char * e_flags_map_arm( int n ){
    switch(n ){
        case 0x01: return "EF_ARM_RELEXEC";
        case 0x02: return "EF_ARM_HASENTRY";
        case 0x04: return "EF_ARM_INTERWORK";
        case 0x08: return "EF_ARM_APCS_26";
        case 0x10: return "EF_ARM_APCS_FLOAT";
        case 0x20: return "EF_ARM_PIC";
        case 0x40: return "EF_ARM_ALIGN8";
        case 0x80: return "EF_ARM_NEW_ABI";
        case 0x100: return "EF_ARM_OLD_ABI";
        case 0x200: return "EF_ARM_SOFT_FLOAT";
        case 0x400: return "EF_ARM_VFP_FLOAT";
        case 0x800: return "EF_ARM_MAVERICK_FLOAT";
        default: return "EF_NONE";
    }
}

//ia64
char * e_flags_map_ia64(int n){
    switch(n){
        case 0x0000000f: return "EF_IA_64_MASKOS";
        case 0x00000010: return "EF_IA_64_ABI64";
        case 0xff000000: return "EF_IA_64_ARCH";
        default: return "EF_NONE";
    }
}

//sh
char * e_flags_map_sh(int n){
    switch(n){
        case 0x1f: return "EF_SH_MACH_MASK";
        case 0x0: return "EF_SH_UNKNOWN";
        case 0x1: return "EF_SH1";
        case 0x2: return "EF_SH2";
        case 0x3: return "EF_SH3";
        case 0x4: return "EF_SH_DSP";
        case 0x5: return "EF_SH3_DSP";
        case 0x6: return "EF_SH4AL_DSP";
        case 0x8: return "EF_SH3E";
        case 0x9: return "EF_SH4";
        case 0xb: return "EF_SH2E";
        case 0xc: return "EF_SH4A";
        case 0xd: return "EF_SH2A";
        case 0x10: return "EF_SH4_NOFPU";
        case 0x11: return "EF_SH4A_NOFPU";
        case 0x12: return "EF_SH4_NOMMU_NOFPU";
        case 0x13: return "EF_SH2A_NOFPU";
        case 0x14: return "EF_SH3_NOMMU";
        case 0x15: return "EF_SH2A_SH4_NOFPU";
        case 0x16: return "EF_SH2A_SH3_NOFPU";
        case 0x17: return "EF_SH2A_SH4";
        case 0x18: return "EF_SH2A_SH3E";
        default: return "EF_NONE";
    }
}

//s/390
char * e_flags_map_s390(int n){
    switch(n){
        case 0x00000001: return "EF_S390_HIGH_GPRS";
        default: return "EF_NONE";
    }
}



// x86
char * sh_type_map_x86_64(int n ){
    switch(n){
        case 1: return "SHT_PROGBITS";
        case 2: return "SHT_SYMTAB";
        case 3: return "SHT_STRTAB";
        case 4: return "SHT_RELA";
        case 5: return "SHT_HASH";
        case 6: return "SHT_DYNAMIC";
        case 7: return "SHT_NOTE";
        case 8: return "SHT_NOBITS";
        case 9: return "SHT_REL";
        case 10: return "SHT_SHLIB";
        case 11: return "SHT_DYNSYM";
        case 14: return "SHT_INIT_ARRAY";
        case 15: return "SHT_FINI_ARRAY";
        case 16: return "SHT_PREINIT_ARRAY";
        case 17: return "SHT_GROUP";
        case 18: return "SHT_SYMTAB_SHNDX";
        case 0x60000000: return "SHT_LOOS";
        case 0x6ffffff5: return "SHT_GNU_ATTRIBUTES";
        case 0x6ffffff6: return "SHT_GNU_HASH";
        case 0x6ffffff7: return "SHT_GNU_LIBLIST";
        case 0x6ffffff8: return "SHT_CHECKSUM";
        case 0x6ffffffa: return "SHT_LOSUNW/SHT_SUNW_move";
        case 0x6ffffffb: return "SHT_SUNW_COMDAT";
        case 0x6ffffffc: return "SHT_SUNW_syminfo";
        case 0x6ffffffd: return "SHT_GNU_verdef";
        case 0x6ffffffe: return "SHT_GNU_verneed";
        case 0x6fffffff: return "SHT_GNU_versym/SHT_HISUNW/SHT_HIOS";
        case 0x70000000: return "SHT_LOPROC";
        case 0x7fffffff: return "SHT_HIPROC";
        case 0x80000000: return "SHT_LOUSER";
        case 0x8fffffff: return "SHT_HIUSER";
    }
    return "SHT_NULL";
}

char * sh_type_map_mips(int n){
    switch(n){
        case 0x70000000: return "SHT_MIPS_LIBLIST";
        case 0x70000001: return "SHT_MIPS_MSYM";
        case 0x70000002: return "SHT_MIPS_CONFLICT";
        case 0x70000003: return "SHT_MIPS_GPTAB";
        case 0x70000004: return "SHT_MIPS_UCODE";
        case 0x70000005: return "SHT_MIPS_DEBUG";
        case 0x70000006: return "SHT_MIPS_REGINFO";
        case 0x70000007: return "SHT_MIPS_PACKAGE";
        case 0x70000008: return "SHT_MIPS_PACKSYM";
        case 0x70000009: return "SHT_MIPS_RELD";
        case 0x7000000b: return "SHT_MIPS_IFACE";
        case 0x7000000c: return "SHT_MIPS_CONTENT";
        case 0x7000000d: return "SHT_MIPS_OPTIONS";
        case 0x70000010: return "SHT_MIPS_SHDR";
        case 0x70000011: return "SHT_MIPS_FDESC";
        case 0x70000012: return "SHT_MIPS_EXTSYM";
        case 0x70000013: return "SHT_MIPS_DENSE";
        case 0x70000014: return "SHT_MIPS_PDESC";
        case 0x70000015: return "SHT_MIPS_LOCSYM";
        case 0x70000016: return "SHT_MIPS_AUXSYM";
        case 0x70000017: return "SHT_MIPS_OPTSYM";
        case 0x70000018: return "SHT_MIPS_LOCSTR";
        case 0x70000019: return "SHT_MIPS_LINE";
        case 0x7000001a: return "SHT_MIPS_RFDESC";
        case 0x7000001b: return "SHT_MIPS_DELTASYM";
        case 0x7000001c: return "SHT_MIPS_DELTAINST";
        case 0x7000001d: return "SHT_MIPS_DELTACLASS";
        case 0x7000001e: return "SHT_MIPS_DWARF";
        case 0x7000001f: return "SHT_MIPS_DELTADECL";
        case 0x70000020: return "SHT_MIPS_SYMBOL_LIB";
        case 0x70000021: return "SHT_MIPS_EVENTS";
        case 0x70000022: return "SHT_MIPS_TRANSLATE";
        case 0x70000023: return "SHT_MIPS_PIXIE";
        case 0x70000024: return "SHT_MIPS_XLATE";
        case 0x70000025: return "SHT_MIPS_XLATE_DEBUG";
        case 0x70000026: return "SHT_MIPS_WHIRL";
        case 0x70000027: return "SHT_MIPS_EH_REGION";
        case 0x70000028: return "SHT_MIPS_XLATE_OLD";
        case 0x70000029: return "SHT_MIPS_PDR_EXCEPTION";
    }
    return "NULL";
}

char * sh_type_map_hppa(int n){
    switch(n){
        case 0x70000000: return "SHT_PARISC_EXT";
        case 0x70000001: return "SHT_PARISC_UNWIND";
        case 0x70000002: return "SHT_PARISC_DOC";
    }
    return NULL;
}

char* sh_type_map_alpha(int n){
    switch(n){
        case 0x70000001: return "SHT_ALPHA_DEBUG";
        case 0x70000002: return "SHT_ALPHA_REGINFO";
    }
    return NULL;
}

char * sh_type_map_arm(int n){
    switch(n){
        case 0x70000001: return "SHT_ARM_EXIDX";
        case 0x70000002: return "SHT_ARM_PREEMPTMAP";
        case 0x70000003: return "SHT_ARM_ATTRIBUTES";
    }
    return NULL;
}

char * sh_type_map_ia64(int n){
    switch(n){
        case 0x70000000: return "SHT_IA_64_EXT";
        case 0x70000001: return "SHT_IA_64_UNWIND";
    }
    return NULL;
}


char * sh_type_map(elf64_t *elf,int n){
    char * ret = NULL;
    switch(elf->ehdr->e_machine){
        case EM_MIPS_RS3_LE:
        case EM_MIPS: 
        case EM_MIPS_X: ret = sh_type_map_mips(n);break;
        case EM_PARISC: ret = sh_type_map_hppa(n);break; //惠普
        case EM_IA_64: ret = sh_type_map_ia64(n);break;
        case EM_ARM : ret = sh_type_map_arm(n);break;
        case EM_ALPHA: ret = sh_type_map_alpha(n);break;
        case EM_PPC:
        case EM_PPC64: 
        case EM_386:
        case EM_X86_64: 
        case EM_NONE:
        case EM_M32:
        case EM_SPARC:
        case EM_68K:
        case EM_88K:
        case EM_860:
        case EM_S370:
        case EM_VPP500:
        case EM_SPARC32PLUS:
        case EM_960:
        case EM_S390:
        case EM_V800:
        case EM_FR20:
        case EM_RH32:
        case EM_RCE:
        case EM_FAKE_ALPHA:
        case EM_SH:
        case EM_SPARCV9:
        case EM_TRICORE:
        case EM_ARC:
        case EM_H8_300:
        case EM_H8_300H:
        case EM_H8S:
        case EM_H8_500:
        case EM_COLDFIRE:
        case EM_68HC12:
        case EM_MMA:
        case EM_PCP:
        case EM_NCPU:
        case EM_NDR1:
        case EM_STARCORE:
        case EM_ME16:
        case EM_ST100:
        case EM_TINYJ:
        case EM_PDSP:
        case EM_FX66:
        case EM_ST9PLUS:
        case EM_ST7:
        case EM_68HC16:
        case EM_68HC11:
        case EM_68HC08:
        case EM_68HC05:
        case EM_SVX:
        case EM_ST19:
        case EM_VAX:
        case EM_CRIS:
        case EM_JAVELIN:
        case EM_FIREPATH:
        case EM_ZSP:
        case EM_MMIX:
        case EM_HUANY:
        case EM_PRISM:
        case EM_AVR:
        case EM_FR30:
        case EM_D10V:
        case EM_D30V:
        case EM_V850:
        case EM_M32R:
        case EM_MN10300:
        case EM_MN10200:
        case EM_PJ:
        case EM_OPENRISC:
        case EM_ARC_A5:
        case EM_XTENSA:
        case EM_AARCH64:
        case EM_TILEPRO:
        case EM_TILEGX:
        case EM_NUM:break;
    }
    return ret?ret:sh_type_map_x86_64(n);        
}
